home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
3D GFX
/
3D GFX.iso
/
pcutils
/
os2
/
rt
/
sil.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-12-30
|
5KB
|
187 lines
/*
SIL.C Simple intersection lists
*/
/*...sincludes:0:*/
#include <stdlib.h>
#include <stddef.h>
#include <memory.h>
#include <math.h>
#include "standard.h"
#include "rt.h"
#include "vector.h"
#define _SIL_
#include "sil.h"
/*...vrt\46\h:0:*/
/*...vvector\46\h:0:*/
/*...vsil\46\h:0:*/
/*...e*/
#define ZERO(x) ( ((x)>=-1.0e-10) && ((x)<=1.0e-10) )
#define SIDESTEP (1.0e6)
/*...sintersect_linear_t:0:*/
void intersect_linear_t(
double coeff_of_t, double constant_term,
VECTOR p, VECTOR q,
void *shapeinfo, double (*value_of_shape)(void *shapeinfo, VECTOR v),
SIL *sil
)
{
if ( ZERO(coeff_of_t) )
/* No intersection with solid surface */
{
if ( (*value_of_shape)(shapeinfo, p) <= 0.0 )
/* Completely in solid */
{
sil->n_sis = 2;
sil->sis[0].t = -INFINITE;
sil->sis[0].entering = TRUE;
sil->sis[1].t = INFINITE;
sil->sis[1].entering = FALSE;
}
else
/* Completely out of solid */
sil->n_sis = 0;
}
else
/* Intersects solid exactly once */
{
double t = - constant_term / coeff_of_t;
sil->n_sis = 2;
sil->sis[0].entering = TRUE;
sil->sis[1].entering = FALSE;
if ( (*value_of_shape)(shapeinfo, t_along_pq(p, q, t+SIDESTEP)) <= 0.0 )
/* Entering solid */
{
sil->sis[0].t = t;
sil->sis[1].t = INFINITE;
}
else
/* Leaving solid */
{
sil->sis[0].t = -INFINITE;
sil->sis[1].t = t;
}
}
}
/*...e*/
/*...sintersect_quadratic_t:0:*/
void intersect_quadratic_t(
double qa, double qb, double qc,
VECTOR p, VECTOR q,
void *shapeinfo, double (*value_of_shape)(void *shapeinfo, VECTOR v),
SIL *sil
)
{
double qs;
if ( ZERO(qa) )
/*...sdo linear case:16:*/
intersect_linear_t(qb, qc, p, q, shapeinfo, value_of_shape, sil);
/*...e*/
else if ( (qs = qb*qb - 4.0*qa*qc) < 0.0 )
/*...sno real roots:16:*/
/* No real roots => no intersections, all solid or all empty */
{
if ( (*value_of_shape)(shapeinfo, p) <= 0.0 )
{
sil->n_sis = 2;
sil->sis[0].t = -INFINITE;
sil->sis[0].entering = TRUE;
sil->sis[1].t = INFINITE;
sil->sis[1].entering = FALSE;
}
else
sil->n_sis = 0;
}
/*...e*/
else if ( ZERO(qs) )
/*...sone double root:16:*/
{
double t = -qb / (qa + qa);
BOOLEAN from_inside = ( (*value_of_shape)(shapeinfo, t_along_pq(p, q, t-SIDESTEP)) <= 0.0 );
BOOLEAN to_inside = ( (*value_of_shape)(shapeinfo, t_along_pq(p, q, t+SIDESTEP)) <= 0.0 );
#define DUAL_SWITCH(f,t) (((f)<<1)+(t))
switch ( DUAL_SWITCH(from_inside, to_inside) )
{
case DUAL_SWITCH(FALSE, FALSE): /* Grazing surface */
sil->n_sis = 0;
break;
case DUAL_SWITCH(FALSE, TRUE): /* Entering solid area */
sil->n_sis = 2;
sil->sis[0].t = t;
sil->sis[0].entering = TRUE;
sil->sis[1].t = INFINITE;
sil->sis[1].entering = FALSE;
break;
case DUAL_SWITCH( TRUE, FALSE): /* Leaving solid area */
sil->n_sis = 2;
sil->sis[0].t = -INFINITE;
sil->sis[0].entering = TRUE;
sil->sis[1].t = t;
sil->sis[1].entering = FALSE;
break;
case DUAL_SWITCH( TRUE, TRUE): /* Never left solid area */
sil->n_sis = 2;
sil->sis[0].t = -INFINITE;
sil->sis[0].entering = TRUE;
sil->sis[1].t = INFINITE;
sil->sis[1].entering = FALSE;
break;
}
}
/*...e*/
else
/*...stwo roots:16:*/
/*
Where I say t1-SIDESTEP, I used to say the more obvious (t1+t2)*0.5.
I changed it because if t1 and t2 are very close, inaccuracies in the
arithmetic can cause the value of shape evaluated at (t1+t2)*0.5 to be just the
wrong side of 0.0. The newer test is much more likely to give the right result
as we are now evaluating the shape function further away from any roots.
*/
{
double rooted = sqrt(qs);
double t1 = (-qb - rooted) / (qa + qa);
double t2 = (-qb + rooted) / (qa + qa);
if ( t1 > t2 )
/* Ensure t1 is lower than t2 */
{ double t = t1; t1 = t2; t2 = t; }
if ( (*value_of_shape)(shapeinfo, t_along_pq(p, q, t1-SIDESTEP)) > 0.0 )
/* Middle part is the solid part */
{
sil->n_sis = 2;
sil->sis[0].t = t1;
sil->sis[0].entering = TRUE;
sil->sis[1].t = t2;
sil->sis[1].entering = FALSE;
}
else
/* Regions before and after middle part are the solid parts */
{
sil->n_sis = 4;
sil->sis[0].t = -INFINITE;
sil->sis[0].entering = TRUE;
sil->sis[1].t = t1;
sil->sis[1].entering = FALSE;
sil->sis[2].t = t2;
sil->sis[2].entering = TRUE;
sil->sis[3].t = INFINITE;
sil->sis[3].entering = FALSE;
}
}
/*...e*/
}
/*...e*/